home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 February: Technology Seed / Mac Tech Seed Feb '97.toast / OpenDoc 1.2b2c1 / OpenDoc / OpenDoc Utilities / Interfaces / Except.h < prev    next >
Encoding:
C/C++ Source or Header  |  1997-01-01  |  12.3 KB  |  440 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        Except.h
  3.  
  4.     Contains:    Exception handling macros
  5.  
  6.     Owned by:    Jens Alfke
  7.  
  8.     Copyright:    © 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <3>     5/24/96    jpa        1246074: Made _NATIVE_EXCEPTIONS_ work
  13.                                     again. 1.1MRD: Speed/size optimizations for
  14.                                     non native exceptions (_ASM_XTRY_.)
  15.          <2>      3/3/96    TJ        Added global gVolatile to help make
  16.                                     ODVolatile realy volatile.
  17.  
  18.     In Progress:
  19.         
  20. */
  21.  
  22.  
  23. /*
  24.     THEORY OF OPERATION
  25.     
  26.     This is a catch/throw based exception handling package which models
  27.     much of the behavior of native C++ exception handling. (Its macros can
  28.     be redefined to use native exceptions if your compiler supports them.)
  29.     
  30.     Reading this header is not recommended for the faint of heart! Here be
  31.     gnarly macros, setjmp fu, and tangled #ifdefs.
  32.     Please see the recipe document "Using Exceptions" for details presented
  33.     in a human-readable fashion.
  34.     
  35.     If the symbol _NATIVE_EXCEPTIONS_ is predefined, native C++ exception
  36.     handling will be used.
  37.     If the symbol _ASM_XTRY_ is predefined, a special assembly-coded
  38.     version of _xTry will be called, which makes the calling code for TRY
  39.     shorter and slightly faster. (This feature still in progress...)
  40. */
  41.  
  42. #ifndef _EXCEPT_
  43. #define _EXCEPT_
  44.  
  45. #ifndef _ODTYPES_
  46. #include "ODTypes.h"
  47. #endif
  48.  
  49. #ifndef _ERRORDEF_
  50.     #ifdef __cplusplus
  51.     #include "ErrorDef.xh"    // Clients probably need the error codes as well
  52.     #else
  53.     #include "ErrorDef.h"
  54.     #endif
  55. #endif
  56.  
  57. #ifndef __SETJMP__
  58. #include <setjmp.h>
  59. #endif
  60.  
  61. #ifdef __LIBRARYMANAGER__
  62. #error "Please don't include both Except.h and LibraryManager.h"
  63. #endif
  64.  
  65.  
  66. #ifdef __MWERKS__
  67. #ifdef __cplusplus
  68.     // The _NATIVE_EXCEPTIONS_ flag must match the Exception Support option:
  69.     #if __option(exceptions)
  70.         #define _NATIVE_EXCEPTIONS_
  71.     #elif defined(_NATIVE_EXCEPTIONS_)
  72.         #if __MWERKS__>=0x0700
  73.             #error Must turn on "Enable Exceptions" to use Except.h with _NATIVE_EXCEPTIONS_
  74.         #else
  75.             #error Must turn off "direct destruction" to use Except.h with _NATIVE_EXCEPTIONS_
  76.         #endif
  77.     #endif
  78. #endif
  79. #endif
  80.  
  81.  
  82. #ifdef _OD_IMPL_SHARE_UTILS_
  83. #pragma import on
  84. #elif defined(PRAGMA_INTERNAL_SUPPORTED)
  85. #pragma internal on
  86. #endif
  87.  
  88. #ifdef __cplusplus
  89. #define EXTERNC extern "C"
  90. #else
  91. #define EXTERNC
  92. #endif
  93.  
  94.  
  95. //=====================================================================================
  96. // ODVolatile
  97. //=====================================================================================
  98.  
  99. // Any variable or parameter that is modified in a TRY block and used in the
  100. // CATCH block must be declared as volatile or it may have an incorrect value
  101. // in the CATCH block.
  102. // Since not all compilers support the 'volatile' keyword, use this instead;
  103.  
  104. #ifndef _NATIVE_EXCEPTIONS_
  105.     #if defined(__SC__) || defined(__MRC__)
  106.         extern void* gVolatile;                        /* Some compilers optimize away &x */
  107.         #define ODVolatile(x)    (gVolatile = &x)
  108.     #else
  109.         #define ODVolatile(x)    ((void)&x)            /* Sufficient for other compilers */
  110.     #endif
  111. #else
  112.     #define ODVolatile(x)                    /*no need for this with native exceptions*/
  113. #endif
  114.  
  115. //=====================================================================================
  116. // Exception Handling Macros (native C++ exceptions)
  117. //=====================================================================================
  118.  
  119. #ifdef _NATIVE_EXCEPTIONS_
  120.  
  121. #define ErrorCode()                (_exception.error)
  122. #define ErrorMessage()            (_exception.message)
  123. #define SetErrorCode(ERR)        (_exception.error=(ERR))
  124. #define SetErrorMessage(MSG)    (strcpy(_exception.error,(MSG))
  125.  
  126. #define TRY                                                    \
  127.                 try {
  128.  
  129. #define CATCH_ALL                                            \
  130.                 } catch(ODException &_exception) {
  131.  
  132. #define RERAISE                                                \
  133.                 throw
  134.  
  135. #define SET_SOM_EXCEPTION(EV)                                \
  136.                 ODSetSOMException(EV,_exception)
  137.  
  138. #define ENDTRY                                                \
  139.                 }
  140.  
  141. /* CATCH( ) will not work with native exceptions. Don't use it! */
  142.  
  143.  
  144. //=====================================================================================
  145. // Exception Handling Macros (emulated)
  146. //=====================================================================================
  147.  
  148. #else /*not _NATIVE_EXCEPTIONS*/
  149.  
  150. #define ErrorCode()                 (_except.fError)
  151. #define ErrorMessage()                (_except.fODException ?_except.fODException->message :kODNULL)
  152. #define SetErrorCode(ERR)            (_xSetErrorCode(&_except,(ERR)))
  153. #define SetErrorMessage(MSG)        (_xSetErrorMessage(&_except,(MSG))
  154.  
  155. #ifndef _ASM_XTRY_
  156.     #define _setjmp_xTry(EX)        setjmp(*_xTry(EX))
  157.     #define _setjmp_xTryEv(EX,EV)    setjmp(*_xTryEv(EX,EV))
  158. #endif
  159.  
  160. #define TRY                                                 \
  161.     {                                                        \
  162.         ODExceptionFrame _except;                            \
  163.         if (_setjmp_xTry(&_except) == 0)                    \
  164.         {
  165.         
  166. #define CATCH_ALL                                            \
  167.         }                                                    \
  168.         else                                                \
  169.         { 
  170.         
  171.         
  172. #define RERAISE                                                \
  173.         _xReraise(&_except)
  174.  
  175. #define SET_SOM_EXCEPTION(EV)                                \
  176.         _xSetSOMException(EV,&_except)
  177.         
  178. #ifdef __cplusplus    
  179. #define ENDTRY                                                \
  180.         }                                                    \
  181.     }
  182. #else // C version:
  183. #define ENDTRY                                                \
  184.         }                                                    \
  185.         _xPop(&_except);                                    \
  186.     }
  187. #endif
  188.  
  189. // CATCH( ) is not compatible with native C++ exceptions and has been obsoleted.
  190. #define CATCH(e)    CATCH_IS_OBSOLETE_USE_CATCH_ALL
  191. //#define CATCH(e)                                            \
  192.         } else if (_except.fError==(e)) {
  193.         
  194.         
  195. #endif /*_NATIVE_EXCEPTIONS*/
  196.  
  197. //=====================================================================================
  198. // Raising Exceptions
  199. //=====================================================================================
  200.  
  201. EXTERNC void THROW(ODError error);
  202. EXTERNC void THROW_IF_ERROR(ODError error);
  203. EXTERNC void THROW_IF_NULL(void* value);
  204.  
  205. // Optional message parameters (ignored in nondebug build):
  206. #if ODDebug
  207. EXTERNC void THROW_IF_ERROR_M(ODError error, const char* msg);
  208. EXTERNC void THROW_M(ODError error, const char* msg);
  209. EXTERNC void THROW_IF_NULL_M(void* value, const char* msg);
  210. #else
  211. #define THROW_IF_ERROR_M(ERR,MSG)    THROW_IF_ERROR(ERR)
  212. #define THROW_M(ERR,MSG)            THROW(ERR)
  213. #define THROW_IF_NULL_M(ERR,MSG)    THROW_IF_NULL(ERR)
  214. #endif
  215.  
  216. #ifdef __cplusplus
  217. // Overloaded C++ equivalents:
  218. inline void THROW_IF_ERROR(ODError error, const char* msg)
  219.                             {THROW_IF_ERROR_M(error,msg);}
  220. inline void THROW(ODError error, const char* msg)
  221.                             {THROW_M(error,msg);}
  222. inline void THROW_IF_NULL(void* value, const char* msg)
  223.                             {THROW_IF_NULL_M(value,msg);}
  224. inline void THROW_IF_NULL(void* value, ODError error)
  225.                             {if ( value == kODNULL ) THROW(error);}
  226. #endif
  227.  
  228. // Call BreakOnThrow(TRUE) to break into the debugger whenever THROW is called.
  229. // (The call returns the previous value of the setting.)
  230. EXTERNC ODBoolean BreakOnThrow( ODBoolean brk );
  231.  
  232.  
  233. //=====================================================================================
  234. // SOM Exception Utilities
  235. //=====================================================================================
  236.  
  237. // This modified TRY block should be used in SOM methods. It's just like a
  238. // regular TRY...CATCH_ALL...ENDTRY except that the exception code will be
  239. // stored in the Environment. Needless to say you should _not_ reraise!
  240. // You should also not make any SOM calls after the SOM_ENDTRY, nor declare any
  241. // Destructo objects before the SOM_TRY.
  242.  
  243. #ifdef _NATIVE_EXCEPTIONS_
  244.  
  245. class EVSetter {    // Used to ensure ev is set at _end_ of catch block
  246.     public:
  247.         EVSetter( Environment* ev, ODException& x )
  248.             :fEv(ev), fEx(x) { }
  249.         ~EVSetter( );
  250.     private:
  251.         Environment *fEv;
  252.         ODException &fEx;
  253. };
  254.  
  255. #define SOM_TRY                                                 \
  256.             TRY
  257.             
  258. #define SOM_CATCH_ALL                                            \
  259.             CATCH_ALL {                                            \
  260.                 EVSetter _evs(ev,_exception);                    \
  261.                 
  262. #define SOM_ENDTRY                                                \
  263.             }                                                    \
  264.             ENDTRY
  265.  
  266. #define SOM_CATCH_ALL_ENDTRY                                    \
  267.             CATCH_ALL                                            \
  268.                 ODSetSOMException(ev,_exception);                \
  269.             ENDTRY                                                \
  270.             // this generates more efficient code.
  271.  
  272. #else /*not _NATIVE_EXCEPTIONS_*/
  273.  
  274. #define SOM_TRY                                                 \
  275.         {                                                        \
  276.             ODExceptionFrame _except;                            \
  277.             if (_setjmp_xTryEv(&_except,ev) == 0)                \
  278.             {
  279.  
  280. #define SOM_CATCH_ALL                                            \
  281.             CATCH_ALL
  282. #define SOM_ENDTRY                                                \
  283.             ENDTRY
  284.  
  285. #define SOM_CATCH_ALL_ENDTRY                                    \
  286.             CATCH_ALL                                            \
  287.             ENDTRY                                                \
  288.  
  289.  
  290. #endif /*_NATIVE_EXCEPTIONS_*/
  291.  
  292.  
  293. // ODSetSOMException stores an OD error code in the environment.
  294. // ODGetSOMException returns the OD error code (if any) from an environment.
  295.  
  296. #ifdef __cplusplus
  297. EXTERNC void    ODSetSOMException( Environment*, ODError, const char *msg =kODNULL );
  298. #else
  299. EXTERNC void    ODSetSOMException( Environment*, ODError, const char *msg );
  300. #endif
  301.  
  302. #ifdef _NATIVE_EXCEPTIONS_
  303. void    ODSetSOMException( Environment*, ODException& );
  304. #endif
  305.  
  306. EXTERNC ODError    ODGetSOMException( Environment *ev );
  307.  
  308. // CHECK_ENV throws an exception if the environment indicates an error.
  309.  
  310. EXTERNC void    CHECK_ENV( Environment* );
  311.  
  312. // SOMCHKEXCEPT is a macro that is called in a .xh file if the ev variable
  313. // indicates an exception is set.
  314. #define SOMCHKEXCEPT {CHECK_ENV(ev);}
  315.  
  316.  
  317. //=====================================================================================
  318. // Obsolete Exception Utilities
  319. //=====================================================================================
  320.  
  321. /*  FN_CATCH and SOM_CATCH are now obsolete. Please convert to regular TRY or SOM_TRY. */
  322. #if 0
  323.  
  324. #if defined(__MWERKS__) || defined(__SC__)
  325.     extern void FN_CATCH_DIDNT_RETURN( );
  326.     /* This function is purposely declared but never defined. Due to the setup of
  327.        the for loop in FN_CATCH and SOM_CATCH, a failure to end the block with a
  328.        return statement will cause the call to FN_CATCH_DIDNT_RETURN not to be
  329.        dead stripped, resulting in a link error. This will help catch this nasty
  330.        coding error. */
  331. #else
  332.     // Other compilers may not dead-strip properly.
  333.     #define FN_CATCH_DIDNT_RETURN() /**/
  334. #endif
  335.  
  336. #define FN_CATCH                                            \
  337.         ODExceptionFrame _except;                            \
  338.         ODVolatile(_except);                                \
  339.         if (_setjmp_xTry(&_except) != 0)                    \
  340.             for( ; true; FN_CATCH_DIDNT_RETURN() )
  341.  
  342. #define SOM_CATCH                                            \
  343.         ODExceptionFrame _except;                            \
  344.         ODVolatile(_except);                                \
  345.         if (_setjmp_xTryEv(&_except,ev) != 0)                \
  346.             for( ; true; FN_CATCH_DIDNT_RETURN() )
  347.  
  348. #endif /*0*/
  349.  
  350. //=====================================================================================
  351. // Finally, the Exception Handler (ODExceptionFrame struct)
  352. //=====================================================================================
  353.  
  354.  
  355. #ifndef _NATIVE_EXCEPTIONS_
  356.  
  357. #ifdef __cplusplus
  358. class Destructo;    // forward declarations for use below
  359. struct ODExceptionFrame;
  360. EXTERNC void _xPop(ODExceptionFrame*);
  361. #else
  362. typedef struct ODExceptionFrame ODExceptionFrame;
  363. typedef struct Destructo Destructo;        // Not used in C but must declare anyway
  364. #endif
  365.  
  366. struct ODExceptionFrame
  367. {
  368.     ODExceptionFrame*    fPrev;
  369.     ODException*        fODException;
  370.     ODError                fError;
  371.     Environment*        fEv;
  372.     Destructo*            fDestructoList;
  373.     jmp_buf                fBuffer;
  374. #ifdef __cplusplus
  375.     void Throw( ODError err, const char* msg, ODException *x =kODNULL );
  376.     inline ~ODExceptionFrame( )    {_xPop(this);}
  377. #endif
  378. };
  379.  
  380. typedef struct ODExceptionFrame ODExceptionFrame;
  381.  
  382. #ifdef _ASM_XTRY_
  383.     EXTERNC int _setjmp_xTry( ODExceptionFrame* );
  384.     EXTERNC int _setjmp_xTryEv( ODExceptionFrame*, Environment* );
  385. #else
  386.     EXTERNC jmp_buf* _xTry( ODExceptionFrame* );
  387.     EXTERNC jmp_buf* _xTryEv( ODExceptionFrame*, Environment* );
  388. #endif
  389.  
  390. EXTERNC void _xReraise( ODExceptionFrame* );
  391. EXTERNC void _xSetSOMException(Environment*,ODExceptionFrame*);
  392. EXTERNC void _xPop( ODExceptionFrame* );
  393. EXTERNC void _xSetErrorCode( ODExceptionFrame*, ODError );
  394. EXTERNC void _xSetErrorMessage( ODExceptionFrame*, const char* );
  395.  
  396. #endif /*_NATIVE_EXCEPTIONS_*/
  397.  
  398.  
  399. //=====================================================================================
  400. // Destructo, a C++ base class for auto-destruct objects
  401. //=====================================================================================
  402.  
  403. #ifdef __cplusplus
  404.  
  405. class Destructo
  406. {
  407. #ifndef _NATIVE_EXCEPTIONS_
  408. protected:
  409.     Destructo( );
  410.     
  411. public:
  412.     virtual ~Destructo( );
  413.     
  414. private:
  415.     Destructo* EmergencyDestruct( );
  416.     Destructo *fPrevDestructo;
  417.     friend class ODExceptionFrame;
  418.  
  419.     static void* operator new( size_t );    // Make it illegal to allocate on heap
  420.                                             // In future could use alloca??
  421.                                             
  422.     private: // disallow these:
  423.     Destructo(const Destructo& );
  424.     void operator=(const Destructo& );
  425.     // Bitwise assigning one destructo to another smashes
  426.     // fPrevDestructo with potentially unpleasant effects.
  427. #endif /*_NATIVE_EXCEPTIONS_*/
  428. };
  429.  
  430. #endif /*__cplusplus*/
  431.  
  432. #ifdef _OD_IMPL_SHARE_UTILS_
  433. #pragma import off
  434. #elif defined(PRAGMA_INTERNAL_SUPPORTED)
  435. #pragma internal off
  436. #endif
  437.  
  438.  
  439. #endif // _EXCEPT_
  440.